package com.ltmonitor.jt808.service.impl;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.annotation.PostConstruct;

import com.ltmonitor.app.GlobalConfig;
import com.ltmonitor.service.IGPSRealDataService;
import com.ltmonitor.util.StringUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.ltmonitor.app.ServiceLauncher;
import com.ltmonitor.dao.IBaseIbatisDao;
import com.ltmonitor.entity.Alarm;
import com.ltmonitor.entity.AlarmRecord;
import com.ltmonitor.entity.BasicData;
import com.ltmonitor.entity.EWayBill;
import com.ltmonitor.entity.VehicleData;
import com.ltmonitor.jt808.service.ITransferGpsService;
import com.ltmonitor.jt808.service.JT809AckItem;
import com.ltmonitor.jt809.entity.DriverModel;
import com.ltmonitor.jt809.entity.VehicleRegisterInfo;
import com.ltmonitor.service.IBasicDataService;
import com.ltmonitor.service.ITransferService;
import com.ltmonitor.service.IVehicleDataService;
import com.ltmonitor.util.Constants;
import com.ltmonitor.util.DateUtil;
import com.ltmonitor.vo.GnssData;
import com.ltmonitor.vo.TakePhotoModel;
import com.ltmonitor.vo.WarnData;
/**
 * 将808的gps数据发送给809
 * @author admin
 *
 */

@Service("transferGpsService")
public class TransferGpsService implements ITransferGpsService {

	/**
	 * 转发实时数据的线程
	 */
	private Thread processRealDataThread;
	/**
	 * 转发报警的线程
	 */
	private Thread processAlarmDataThread;

	/**
	 * 远程调用809服务器的RPC服务
	 */
	private ITransferService tService;

	@Autowired
	private IBasicDataService basicDataService;
	/**
	 * 是否启用809转发
	 */
	@Value("${config.transferTo809Enabled:true}")
	private boolean transferTo809Enabled = true;
	/**
	 * 是否转发报警到809
	 */
	@Value("${config.transferAlarmTo809Enabled:true}")
	private boolean transferAlarmTo809Enabled = true;

	private boolean continueTransfer;

	@Autowired
	private IVehicleDataService vehicleDataService;

	@Autowired
	private IGPSRealDataService realDataService;

	@Autowired
	IBaseIbatisDao baseIbatisDao;

	private static Logger logger = Logger.getLogger(TransferGpsService.class);

	private ConcurrentLinkedQueue<JT809AckItem> jt809AckQueue = new ConcurrentLinkedQueue<JT809AckItem>();

	private ConcurrentLinkedQueue<GnssData> dataQueue = new ConcurrentLinkedQueue<GnssData>();

	private ConcurrentLinkedQueue<VehicleRegisterInfo> vehicleRegisterInfoQueue = new ConcurrentLinkedQueue<VehicleRegisterInfo>();

	/**
	 * 转发定位数据的队列
	 */
	private ConcurrentLinkedQueue<GnssData> gnssDataQueueWaitForSend = new ConcurrentLinkedQueue<GnssData>();

	@PostConstruct
	public void start() {
		continueTransfer = true;
		if (isTransferTo809Enabled()) {
			processRealDataThread = new Thread(new Runnable() {
				public void run() {
					ProcessRealDataThreadFunc();
				}
			});
			processRealDataThread.start();

			processAlarmDataThread = new Thread(new Runnable() {
				public void run() {
					ProcessAlarmDataThreadFunc();
				}
			});
			processAlarmDataThread.start();

		}
	}

	public void stop() {
		continueTransfer = false;
		if (processRealDataThread != null) {
			try {
				processRealDataThread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		if (processAlarmDataThread != null) {
			try {
				processAlarmDataThread.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void ProcessRealDataThreadFunc() {
		while (continueTransfer && transferTo809Enabled) {
			Date start = new Date();
			try {
				if (this.tService != null && this.tService.isMainLinked()
						&& this.tService.isSubLinked()) {
					this.sendHisData();
				}
				JT809AckItem ack = this.jt809AckQueue.poll();
				int count = 0;
				while (ack != null && count < 100) {
					this.sendJt809Ack(ack);
					ack = jt809AckQueue.poll();
					count++;
				}

				VehicleRegisterInfo vm = vehicleRegisterInfoQueue.poll();
				int viCount = 0;
				while (vm != null && viCount < 50) {
					this.getTransferService().UpExgMsgRegister(vm);
					vm = vehicleRegisterInfoQueue.poll();
					viCount++;
				}

				if (dataQueue.size() > 200000) {
					logger.error("数据队列过大:" +dataQueue.size());
					int m = 0;
					while (m++ < 100) {
						dataQueue.poll();
					}
				}
				GnssData tm = dataQueue.poll();
				count = 0;
				while (tm != null && count < 80) {
					transferTo809(tm);
					tm = dataQueue.poll();
					count++;
				}
				Date end = new Date();
				double seconds = DateUtil.getSeconds(start, end);
				if (seconds > 0.8) {
					logger.error("转发实时数据耗时:" + seconds + ",数量" + count);
				}
				GlobalConfig.waitFor809TransferNum = dataQueue.size();
				GlobalConfig.realDataWaitForSendNum = gnssDataQueueWaitForSend.size();

				GlobalConfig.jt809serverConnected = true;
			} catch (Exception ex) {
				GlobalConfig.jt809serverConnected = false;
				logger.error(ex.getMessage(), ex);
				// logger.error(ex.getStackTrace());
			}

			try {
				Thread.sleep(30L);
			} catch (InterruptedException e1) {
			}
		}
	}

	private void sendHisData() {
		if (gnssDataQueueWaitForSend.isEmpty() == false) {
			try {
				Thread.sleep(GlobalConfig.reportHistoryDelay);
				logger.error("延迟发送:" + GlobalConfig.reportHistoryDelay);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			HashMap<String, List<GnssData>> gnssDataMap = new HashMap<String, List<GnssData>>();
			List<GnssData> gnssDataList = new ArrayList<GnssData>();
			while (gnssDataQueueWaitForSend.isEmpty() == false) {
				GnssData g = gnssDataQueueWaitForSend.poll();
				if (g != null) {
					if (gnssDataMap.containsKey(g.getPlateNo()) == false) {
						gnssDataList = new ArrayList<GnssData>();
						gnssDataMap.put(g.getPlateNo(), gnssDataList);
					}
					gnssDataList = gnssDataMap.get(g.getPlateNo());
					gnssDataList.add(g);
					if (gnssDataList.size() == 5) {
						this.tService.UpExgMsgHistoryLocations(g.getPlateNo(),
								g.getPlateColor(), gnssDataList);

						GlobalConfig.totalTransferNum+=gnssDataList.size();
						gnssDataList.clear();
					}
				}
			}
			Collection<List<GnssData>> keys = gnssDataMap.values();
			for (List<GnssData> gnssDataList1 : keys) {
				if (gnssDataList1.size() > 0) {
					GnssData g = gnssDataList1.get(0);
					this.tService.UpExgMsgHistoryLocations(g.getPlateNo(),
							g.getPlateColor(), gnssDataList1);
					GlobalConfig.totalTransferNum+=gnssDataList.size();
					gnssDataList1.clear();
				}
			}
		}

	}

	/**
	 * 转发报警的线程函数
	 */
	private void ProcessAlarmDataThreadFunc() {
		while (continueTransfer) {
			try {
				transferAlarmDataFromDb();
			} catch (Exception ex) {
				logger.error(ex.getMessage());
				// logger.error(ex.getStackTrace());
			}
			try {
				Thread.sleep(50L);
			} catch (InterruptedException e1) {
			}
		}
	}

	private void sendJt809Ack(JT809AckItem ack) {
		if (ack.getMsgId().equals(JT809AckItem.UpWarnMsgAdptInfo)) {
			//报警信息
			WarnData warnData = (WarnData) ack.getMsgData();
			getTransferService().UpWarnMsgAdptInfo(warnData);
		} else if (ack.getMsgId().equals(
				JT809AckItem.UpExgMsgReportTakeEWayBill)) {
			//电子运单应答
			EWayBill ebill = (EWayBill) ack.getMsgData();
			getTransferService().UpExgMsgReportTakeEWayBill(ebill.getPlateNo(),
					ebill.getPlateColor(), ebill.geteContent());

		} else if (ack.getMsgId().equals(JT809AckItem.UpCtrlMsgTakePhotoAck)) {
			//拍照信息应答
			TakePhotoModel ph = (TakePhotoModel) ack.getMsgData();
			getTransferService().UpCtrlMsgTakePhotoAck(ph);
		} else if (ack.getMsgId().equals(JT809AckItem.UpExgMsgReportDriverInfo)) {
			//驾驶员信息
			DriverModel d = (DriverModel) ack.getMsgData();
			getTransferService().UpExgMsgReportDriverInfo(d);
		} else if (ack.getMsgId().equals(
				JT809AckItem.UpCtrlMsgMonitorVehicleAck)) {
			//车辆监管应答
			byte result = (Byte) ack.getMsgData();
			getTransferService().UpCtrlMsgMonitorVehicleAck(ack.getPlateNo(),
					ack.getPlateColor(), result);
		} else if (ack.getMsgId().equals(JT809AckItem.UpCtrlMsgTakeTravelAck)) {
			//行车记录仪应答
			byte[] cmdData = (byte[]) ack.getMsgData();
			getTransferService().UpCtrlMsgTakeTravelAck(ack.getPlateNo(),
					ack.getPlateColor(), (byte) ack.getCmdType(), cmdData);
		} else if (ack.getMsgId().equals(JT809AckItem.UpCtrlMsgTextInfoAck)) {
			// 文本下发应答
			byte result = (Byte) ack.getMsgData();
			getTransferService().UpCtrlMsgTextInfoAck(ack.getPlateNo(),
					ack.getPlateColor(), ack.getCmdType(), result);

		} else if (ack.getMsgId().equals(
				JT809AckItem.UpCtrlMsgEmergencyMonitoringAck)) {
			// 紧急接入应答
			byte result = (Byte) ack.getMsgData();
			getTransferService().UpCtrlMsgEmergencyMonitoringAck(
					ack.getPlateNo(), ack.getPlateColor(), result);

		}

	}

	/**
	 * 转发拍照数据
	 * @param ph
	 */
	@Override
	public void transfer(TakePhotoModel ph) {
		if (transferTo809Enabled == false)
			return;

		JT809AckItem ack = new JT809AckItem(JT809AckItem.UpCtrlMsgTakePhotoAck,
				ph);
		this.jt809AckQueue.offer(ack);
	}

	public void transferRegisterInfo(VehicleRegisterInfo vm) {
		if (transferTo809Enabled == false)
			return;

		if (vm.getPlateNo() != null && vm.getPlateNo().indexOf("测B0") >= 0)
			this.vehicleRegisterInfoQueue.add(vm);
		else if(this.getTransferService() != null)
			this.getTransferService().UpExgMsgRegister(vm);
	}

	/**
	 * 转发记录仪数据
	 */
	@Override
	public void transferRecorderData(String plateNo, int plateColor,
									 byte cmdType, byte[] cmdData) {
		if (transferTo809Enabled == false)
			return;

		JT809AckItem ack = new JT809AckItem(
				JT809AckItem.UpCtrlMsgTakeTravelAck, plateNo, plateColor,
				cmdData);
		ack.setCmdType(cmdType);
		this.jt809AckQueue.offer(ack);
	}

	public void transferDriverInfo(DriverModel d) {
		if (transferTo809Enabled == false || getTransferService() == null)
			return;

		JT809AckItem ack = new JT809AckItem(
				JT809AckItem.UpExgMsgReportDriverInfo, d);
		this.jt809AckQueue.offer(ack);
	}

	/**
	 * 转发文本信息应答数据
	 */
	@Override
	public void transferTextInfoAck(String plateNo, int plateColor, int msgId,
									byte result) {
		if (transferTo809Enabled == false)
			return;

		JT809AckItem ack = new JT809AckItem(JT809AckItem.UpCtrlMsgTextInfoAck,
				plateNo, plateColor, result);
		ack.setCmdType(msgId);
		this.jt809AckQueue.offer(ack);
	}

	/**
	 * 转发紧急接入应答
	 */
	@Override
	public void transferEmergencyAccessAck(String plateNo, int plateColor,
										   byte result) {
		if (transferTo809Enabled == false)
			return;

		JT809AckItem ack = new JT809AckItem(
				JT809AckItem.UpCtrlMsgEmergencyMonitoringAck, plateNo,
				plateColor, result);

		boolean re = this.jt809AckQueue.offer(ack);
	}

	@Override
	public void transferListenTerminalAck(String plateNo, int plateColor,
										  byte result) {
		if (transferTo809Enabled == false)
			return;

		JT809AckItem ackItem = new JT809AckItem(
				JT809AckItem.UpCtrlMsgMonitorVehicleAck, plateNo, plateColor,
				result);
		this.jt809AckQueue.offer(ackItem);

	}

	/**
	 * 电子运单
	 * @param ebill
	 */
	@Override
	public void transfer(EWayBill ebill) {
		if (transferTo809Enabled == false || getTransferService() == null)
			return;
		JT809AckItem ackItem = new JT809AckItem(
				JT809AckItem.UpExgMsgReportTakeEWayBill, ebill);
		this.jt809AckQueue.offer(ackItem);
	}

	private ITransferService getTransferService() {
		if (tService == null) {
			try {
				tService = (ITransferService) ServiceLauncher
						.getBean("transferService");
			} catch (Exception ex) {
				logger.error(ex.getMessage());
			}
		}
		return tService;
	}

	/**
	 * 转发定位数据
	 */
	@Override
	public void transfer(GnssData gd) {
		if (this.transferTo809Enabled == false)
			return;

		if (tService == null) {
			try {
				tService = (ITransferService) ServiceLauncher
						.getBean("transferService");
			} catch (Exception ex) {
				logger.error(ex.getMessage());
				return;
			}
		}
		if (gd.getPlateNo() != null && gd.getPlateNo().indexOf("测B0") >= 0)
			dataQueue.add(gd);
		else {
			if (tService != null && tService.isMainLinked() == false
					&& tService.isSubLinked() == false) {
				this.gnssDataQueueWaitForSend.offer(gd);
			} else {
				tService.UpExgMsgRealLocation(gd);
				GlobalConfig.totalTransferNum+=1;
			}
		}
	}


	@Override
	public void transfer(Alarm ar) {
		if (transferTo809Enabled == false || getTransferService() == null)
			return;
		String alarmType = ar.getAlarmType();
		VehicleData vd = vehicleDataService.load(ar.getVehicleId());
		if (vd == null) {
			logger.error("转发报警的时候，找不到车辆:" + ar.getPlateNo() + "的信息");
			return;
		}
		WarnData wd = new WarnData();
		wd.setPlateNo(ar.getPlateNo());
		wd.setPlateColor(vd.getPlateColor());
		wd.setInfoId(ar.getEntityId());
		if (AlarmRecord.ALARM_FROM_PLATFORM.equals(ar.getAlarmSource()))
			wd.setSrc(WarnData.FROM_PLATFROM);
		else
			wd.setSrc(WarnData.FROM_TERMINAL);
		wd.setWarnTime(ar.getAlarmTime());
		BasicData bd = basicDataService.getBasicDataByCode(ar.getAlarmType(),
				"AlarmType");
		wd.setContent(bd != null ? bd.getName() : "");
		int warnType = getWarnType(alarmType);
		wd.setType(warnType);
		JT809AckItem item = new JT809AckItem(JT809AckItem.UpWarnMsgAdptInfo, wd);
		this.jt809AckQueue.offer(item);
	}

	private int getWarnType(String alarmType) {
		int warnType = 0;
		if (alarmType.equals("0"))
			warnType = WarnData.EMERGENCY;
		else if (alarmType.equals("1"))
			warnType = WarnData.OVER_SPEED;
		else if (alarmType.equals("2"))
			warnType = WarnData.TIRED;
		else if (alarmType.equals(AlarmRecord.TYPE_IN_AREA))
			warnType = WarnData.IN_AREA;
		else if (alarmType.equals(AlarmRecord.TYPE_CROSS_BORDER))
			warnType = WarnData.OUT_AREA;
		else if (alarmType.equals(AlarmRecord.TYPE_OFFSET_ROUTE))
			warnType = WarnData.OFFSET_ROUTE;
		else
			warnType = WarnData.OTHER;
		return warnType;
	}

	Map<String, Date> alarmMap = new HashMap<String, Date>();



	/**
	 * 从数据库中转发最新的报警信息
	 */
	private void transferAlarmDataFromDb() {
		if (this.isTransferTo809Enabled() == false)
			return;

		String queryId = "selectLatestAlarms";
		Map params = new HashMap();
		String tableName = Constants.getAlarmTableName();
		params.put("tableName", tableName);
		Date date = DateUtil.getDate(new Date(), Calendar.MINUTE, -1); //获取最新的报警信息
		params.put("startTime", date);
		// params.put("status", "New");
		List alarmList = this.baseIbatisDao.query(queryId, params);

		if (alarmList.size() == 0) {
			alarmMap.clear();
		}
		// List result = new ArrayList();
		for (Object obj : alarmList) {
			try {
				Map rowData = (Map) obj;
				Integer alarmId = (Integer) rowData.get("id");
				Integer depId = (Integer) rowData.get("depId");
				String key = "_" + alarmId;
				if (alarmMap.containsKey(key) == false) {
					alarmMap.put(key, new Date());

					String alarmType = "" + rowData.get("alarmType");

					if (AlarmRecord.TYPE_ONLINE.equals(alarmType)
							|| AlarmRecord.TYPE_OFFLINE.equals(alarmType)
							|| AlarmRecord.TYPE_ACC.equals(alarmType)) {
						continue;
					}

					String plateNo = "" + rowData.get("plateNo");
					String alarmSource = "" + rowData.get("alarmSource");
					int vehicleId = (Integer) rowData.get("vehicleId");
					Date alarmTime = (Date) rowData.get("alarmTime");
					double latitude = Double.parseDouble(""
							+ rowData.get("latitude"));
					double longitude = Double.parseDouble(""
							+ rowData.get("longitude"));
					double speed = Double
							.parseDouble("" + rowData.get("speed"));
					String location = "" + rowData.get("location");

					Alarm ar = new Alarm();
					ar.setEntityId(alarmId);
					ar.setVehicleId(vehicleId);
					ar.setPlateNo(plateNo);
					ar.setAlarmTime(alarmTime);
					ar.setLatitude(latitude);
					ar.setLongitude(longitude);
					ar.setSpeed(speed);
					ar.setAlarmType(alarmType);
					ar.setAlarmSource(alarmSource);
					ar.setLocation(location);

					this.transfer(ar);

				}
			} catch (Exception ex) {
				logger.error(ex.getMessage(), ex);
			}

		}

	}

	private void transferTo809(GnssData gd) {
		if (transferTo809Enabled == false)
			return;
		tService.UpExgMsgRealLocation(gd);
		GlobalConfig.totalTransferNum+=1;
	}


	public boolean isTransferTo809Enabled() {
		return transferTo809Enabled;
	}

	public void setTransferTo809Enabled(boolean transferTo809Enabled) {
		this.transferTo809Enabled = transferTo809Enabled;
	}

	public boolean isTransferAlarmTo809Enabled() {
		return transferTo809Enabled && transferAlarmTo809Enabled;
	}

	public void setTransferAlarmTo809Enabled(boolean transferAlarmTo809Enabled) {
		this.transferAlarmTo809Enabled = transferAlarmTo809Enabled;
	}


}
